package com.ruoyi.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.constant.CacheKeyConstants;
import com.ruoyi.common.constant.ResultConstants;
import com.ruoyi.common.exception.BusinessException;
import com.ruoyi.common.support.Convert;
import com.ruoyi.common.utils.AESUtil;
import com.ruoyi.common.utils.BigDecimalUtil;
import com.ruoyi.common.utils.RandomStringUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.WdyBuyProduct;
import com.ruoyi.system.domain.WdyRecharge;
import com.ruoyi.system.domain.WdyUser;
import com.ruoyi.system.mapper.WdyUserMapper;
import com.ruoyi.system.service.IWdyBuyProductService;
import com.ruoyi.system.service.IWdyRechargeService;
import com.ruoyi.system.service.IWdyUserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.web3j.crypto.Credentials;
import org.web3j.crypto.WalletUtils;

import java.io.File;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 用户 服务层实现
 *
 * @author ruoyi
 * @date 2019-03-14
 */
@Service
public class WdyUserServiceImpl extends ServiceImpl<WdyUserMapper, WdyUser> implements IWdyUserService {



    protected Logger log = LoggerFactory.getLogger(this.getClass());


    @Autowired
    protected RedisTemplate redisTemplate;

    @Autowired
    protected IWdyBuyProductService wdyBuyProductService;
    @Autowired
    protected IWdyRechargeService wdyRechargeService;
    /**
     * 查询用户信息
     *
     * @param id 用户ID
     * @return 用户信息
     */
    @Override
    public WdyUser selectWdyUserById(Long id) {
        return baseMapper.selectWdyUserById(id);
    }

    /**
     * 查询用户列表
     *
     * @param wdyUser 用户信息
     * @return 用户集合
     */
    @Override
    public List<WdyUser> selectWdyUserList(WdyUser wdyUser) {
        return baseMapper.selectWdyUserList(wdyUser);
    }

    /**
     * 新增用户
     *
     * @param wdyUser 用户信息
     * @return 结果
     */
    @Override
    public int insertWdyUser(WdyUser wdyUser) {
        return baseMapper.insertWdyUser(wdyUser);
    }

    /**
     * 修改用户
     *
     * @param wdyUser 用户信息
     * @return 结果
     */
    @Override
    public int updateWdyUser(WdyUser wdyUser) {
        return baseMapper.updateWdyUser(wdyUser);
    }

    /**
     * 删除用户对象
     *
     * @param ids 需要删除的数据ID
     * @return 结果
     */
    @Override
    public int deleteWdyUserByIds(String ids) {
        return baseMapper.deleteWdyUserByIds(Convert.toStrArray(ids));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void register(WdyUser user) {
        WdyUser wdyUser = new WdyUser();
        wdyUser.setUserId(RandomStringUtils.getRandomUUID());
        wdyUser.setUserName(user.getUserName());
        wdyUser.setMobilePhone(user.getMobilePhone());
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        wdyUser.setPassword(passwordEncoder.encode(user.getPassword()));
        wdyUser.setReferrerCode(RandomStringUtils.getRandomString(6));
        String referrerCode = user.getReferrerCode().trim();
        if (StringUtils.isNotEmpty(referrerCode)) {
            QueryWrapper<WdyUser> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("referrer_code", referrerCode);
            WdyUser referrer = this.getOne(queryWrapper);
            if(referrer == null) {
                throw new BusinessException(ResultConstants.EX9110, "邀请码无效");
            }
            wdyUser.setReferrerId(referrer.getUserId());
            if(StringUtils.isEmpty(referrer.getLeaderId())) {
                wdyUser.setLeaderId(referrer.getUserId());
            } else {
                wdyUser.setLeaderId(referrer.getLeaderId());
            }
        }

        try {
            File dir = new File((System.getProperty("os.name").toLowerCase().startsWith("win") ? "D:" : "") + WdyUser.WALLET_DIR);
            if(!dir.exists()) {
                dir.mkdirs();
            }
            String walletFileName = WalletUtils.generateFullNewWalletFile(WdyUser.WALLET_PWD, dir);
            String source = dir.getAbsolutePath() + "/" + walletFileName;
            Credentials credentials = WalletUtils.loadCredentials(WdyUser.WALLET_PWD, source);
            wdyUser.setWalletAddress(credentials.getAddress());
            wdyUser.setWalletPrivateKey(AESUtil.encrypt(credentials.getEcKeyPair().getPrivateKey().toString(16)));
        } catch (Exception e) {
            log.error("生成钱包异常", e);
            throw new BusinessException(ResultConstants.EX9110, "系统繁忙，请稍后重试");
        }

        this.save(wdyUser);
    }

    @Override
    public Map<String, Object> getReferrerStatistic(String userId, String startDate, String endDate, Map<String, Map<String, Object>> teamMap) {
        QueryWrapper<WdyUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("user_id", "user_name as name", "level", "referrer_id", "create_time");
        queryWrapper.eq("user_id", userId);
        Map<String, Object> user = this.getMap(queryWrapper);
        Map<String, BigDecimal> rankmap = new HashMap<>();

        return getUserListByReferrers(user, 1, startDate, endDate, rankmap, teamMap);
    }

    private Map<String, Object> getUserListByReferrers(Map<String, Object> user, int level, String startDate, String endDate, Map<String, BigDecimal> rankmap, Map<String, Map<String, Object>> teamMap) {
        String userId = String.valueOf(user.get("user_id"));

        BigDecimal recharge = (BigDecimal) redisTemplate.opsForHash().get(CacheKeyConstants.RECHARGE_AMOUNT, userId);
        if(recharge == null) {
            QueryWrapper<WdyRecharge> rechargeQueryWrapper = new QueryWrapper<>();
            rechargeQueryWrapper.select("IFNULL(SUM(amount),0) AS amount");
            rechargeQueryWrapper.eq("user_id", userId);
            recharge = (BigDecimal) wdyRechargeService.getMap(rechargeQueryWrapper).get("amount");
            redisTemplate.opsForHash().put(CacheKeyConstants.RECHARGE_AMOUNT, userId, recharge);
        }

        Map<String, Object>  buyProductMap = (Map<String, Object>) redisTemplate.opsForHash().get(CacheKeyConstants.BUY_PRODUCT, userId);
        if(buyProductMap == null) {
            QueryWrapper<WdyBuyProduct> buyProductQueryWrapper = new QueryWrapper<>();
            buyProductQueryWrapper.select("IFNULL(SUM(cnn_amount),0) AS amount", "COUNT(1) as count");
            buyProductQueryWrapper.eq("user_id", userId);
            buyProductMap = wdyBuyProductService.getMap(buyProductQueryWrapper);
            redisTemplate.opsForHash().put(CacheKeyConstants.BUY_PRODUCT, userId, buyProductMap);
        }

        BigDecimal buyProduct = (BigDecimal) buyProductMap.get("amount");
        Long buyProductCount = (Long) buyProductMap.get("count");

        QueryWrapper<WdyUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("user_id", "user_name as name", "level", "referrer_id", "create_time");
        queryWrapper.eq("referrer_id", userId);
        queryWrapper.le("create_time", endDate + " 23:59:59");
        List<Map<String, Object>> children = this.listMaps(queryWrapper);

        Integer childrenCount = 0;//所有子节点数
        Integer directChildrenCount = children == null ? 0 : children.size();

        childrenCount += directChildrenCount;
        BigDecimal teamRecharge = BigDecimal.ZERO;
        BigDecimal teamBuyProduct = BigDecimal.ZERO;
        Long directChildrenBuyProductCount = 0l;
        Long teamBuyProductCount = 0l;
        if (children != null && !children.isEmpty()) {
            for (Map<String, Object> map : children) {
                getUserListByReferrers(map, level + 1, startDate, endDate, rankmap, teamMap);
                childrenCount += (Integer) map.get("childrenCount");
                teamRecharge = teamRecharge.add((BigDecimal) map.get("recharge")).add((BigDecimal) map.get("teamRecharge"));
                teamBuyProduct = teamBuyProduct.add((BigDecimal) map.get("buyProduct"));
                directChildrenBuyProductCount += (Long) map.get("buyProductCount");
                teamBuyProductCount += (Long) map.get("buyProductCount") + (Long) map.get("teamBuyProductCount");
            }
        }
        user.put("children", children);
        user.put("directChildrenCount", directChildrenCount);
        user.put("childrenCount", childrenCount);
        user.put("recharge", recharge);
        user.put("buyProduct", buyProduct);
        user.put("buyProductCount", buyProductCount);
        user.put("teamRecharge", BigDecimalUtil.getP2BigDecimal(teamRecharge));
        user.put("teamBuyProduct", BigDecimalUtil.getP2BigDecimal(teamBuyProduct));
        user.put("directChildrenBuyProductCount", directChildrenBuyProductCount);
        user.put("teamBuyProductCount", teamBuyProductCount);
        teamMap.put(userId, user);

        return user;
    }
}
